# 开发服务器

Rsbuild 配备了一个内置的开发服务器，旨在提升开发体验。当你执行 `rsbuild dev` 或 `rsbuild preview` 命令时，该服务器将启动，并提供页面预览、路由、模块热更新等功能。

## 服务端基础路径

默认情况下，服务端的基础路径为 `/`，用户可通过 http://localhost:3000/ 访问到 `index.html` 等产物资源、以及 public 目录下的资源。

Rsbuild 支持通过 [server.base](/config/server/base) 修改服务端的基础路径。当我们希望通过 http://localhost:3000/foo/ 访问到这些资源时，可以添加如下配置：

```ts title="rsbuild.config.ts"
export default {
  server: {
    base: '/foo',
  },
};
```

## 查看静态资源

启动 dev server 后，你可以访问 `/rsbuild-dev-server` 查看 Rsbuild 在当前构建中生成的所有静态资源。

例如，在浏览器中打开 `http://localhost:3000/rsbuild-dev-server`，可以看到：

<img
  src="https://assets.rspack.dev/rsbuild/assets/assets-report-page.png"
  alt="rsbuild-dev-server"
  width="600"
/>

## 页面路由

Rsbuild 的 Server 提供一套默认的路由约定，并允许用户通过配置项定制。

### 默认行为

Rsbuild Server 会根据 [server.base](/config/server/base) 和 [source.entry](/config/source/entry) 配置生成对应的页面路由。

当 entry 为 index 时，可通过 `/` 访问页面；当 entry 为 foo 时，可通过 `/foo` 访问该页面。

当 server.base 为 `/base` 时，可通过 `/base` 访问 index 页面，通过 `/base/foo` 访问 foo 页面。

```ts title="rsbuild.config.ts"
export default {
  source: {
    entry: {
      index: './src/index.ts',
      foo: './src/pages/foo/index.ts',
    },
  },
};
```

### Fallback 行为

当请求满足以下条件且未找到对应资源时，会被 `server.htmlFallback` 处理，默认会回退到 index.html。

- 当前请求是 GET 或 HEAD 请求
- 当前请求头接受 `text/html` (请求头 accept 类型为 `text/html` 或 `*/*`)

```ts title=rsbuild.config.ts
export default {
  server: {
    htmlFallback: 'index',
  },
};
```

### 自定义 Fallback 行为

当 Rsbuild 默认的 [server.htmlFallback](/config/server/html-fallback) 配置无法满足你的需求，例如，希望在访问 `/` 时可以访问 `main.html`，可通过 [server.historyApiFallback](/config/server/history-api-fallback) 进行设置。

```ts title=rsbuild.config.ts
export default {
  source: {
    entry: {
      main: './src/index.ts',
    },
  },
  server: {
    htmlFallback: false,
    historyApiFallback: {
      index: '/main.html',
    },
  },
};
```

### HTML 输出路径

通常情况下，`/` 指向 dist 产物根目录， 而 HTML 文件输出到 dist 根目录下，此时可通过 `/some-path` 访问对应的 HTML 页面。

若通过修改 [output.distPath.html](/config/output/dist-path) 将 HTML 文件输出到其他子目录下，此时需通过 `/[htmlPath]/some-path` 访问对应的 HTML 页面。

例如，设置将 HTML 文件输出到 `HTML` 目录下，此时将通过 `/html/` 访问到 index.html，通过 `/html/foo` 访问到 foo.html。

```ts
export default {
  source: {
    entry: {
      index: './src/index.ts',
      foo: './src/pages/foo/index.ts',
    },
  },
  output: {
    distPath: {
      html: 'html',
    },
  },
};
```

## Rspack Dev Server

Rspack CLI 内置的开发服务器是 [@rspack/dev-server](https://www.npmjs.com/package/@rspack/dev-server)，Rsbuild 没有使用 `@rspack/dev-server`，而是自行实现了一个更轻量的版本。

### 对比

Rsbuild 的开发服务器和 `@rspack/dev-server` 有以下区别：

- **配置项**：Rsbuild 提供了更丰富的 server 配置项。
- **日志格式**：Rspack CLI 日志格式与 Webpack CLI 基本一致，而 Rsbuild 的日志则更加清晰和易读。
- **底层依赖**：`@rspack/dev-server` 基于 express 实现，三方依赖较多。Rsbuild 则采用 `connect` 等更轻量的库实现。

### 配置项

Rsbuild 不支持使用 Rspack 的 [devServer](https://rspack.dev/config/dev-server) 配置项，你可以使用 Rsbuild 的 `dev` 和 `server` 配置代替。

在 Rsbuild 里，`dev` 包含一些仅在开发阶段生效的配置，而 `server` 配置对开发服务器和 preview 服务器均能生效。

以下是 Rspack CLI 的 `devServer` 配置对应的 Rsbuild 配置：

| Rspack CLI                                                                                       | Rsbuild                                                          |
| ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- |
| [devServer.client](https://rspack.dev/config/dev-server#devserverclient)                         | [dev.client](/config/dev/client)                                 |
| [devServer.compress](https://rspack.dev/config/dev-server#devservercompress)                     | [server.compress](/config/server/compress)                       |
| [devServer.headers](https://rspack.dev/config/dev-server#devserverheaders)                       | [server.headers](/config/server/headers)                         |
| [devServer.historyApiFallback](https://rspack.dev/config/dev-server#devserverhistoryapifallback) | [server.historyApiFallback](/config/server/history-api-fallback) |
| [devServer.host](https://rspack.dev/config/dev-server#devserverhost)                             | [server.host](/config/server/host)                               |
| [devServer.hot](https://rspack.dev/config/dev-server#devserverhot)                               | [dev.hmr](/config/dev/hmr)                                       |
| [devServer.liveReload](https://rspack.dev/config/dev-server#devserverlivereload)                 | [dev.liveReload](/config/dev/live-reload)                        |
| [devServer.open](https://rspack.dev/config/dev-server#devserveropen)                             | [server.open](/config/server/open)                               |
| [devServer.port](https://rspack.dev/config/dev-server#devserverport)                             | [server.port](/config/server/port)                               |
| [devServer.proxy](https://rspack.dev/config/dev-server#devserverproxy)                           | [server.proxy](/config/server/proxy)                             |
| [devServer.setupMiddlewares](https://rspack.dev/config/dev-server#devserversetupmiddlewares)     | [dev.setupMiddlewares](/config/dev/setup-middlewares)            |
| [devServer.static](https://rspack.dev/config/dev-server#devserverstatic)                         | [server.publicDir](/config/server/public-dir)                    |
| [devServer.watchFiles](https://rspack.dev/config/dev-server#devserverwatchfiles)                 | [dev.watchFiles](/config/dev/watch-files)                        |

> 更多配置请参考 [Config 总览](/config/index)。

## 扩展中间件

Rsbuild server 未使用任何 Node.js 框架，Rsbuild 中间件提供的 req 和 res 均为 Node.js 原生对象。
这意味着，当你从其他服务端框架迁移时（如 Express），原本的中间件不一定能直接在 Rsbuild 中使用，例如，无法在 Rsbuild 中间件中访问 Express 所提供的 `req.params`、`req.path`、`req.search`、`req.query` 等属性。

如果你需要在 Rsbuild 中使用原有的中间件，可以采取以下方式，将服务端应用作为中间件传入：

```ts title="rsbuild.config.ts"
import expressMiddleware from 'my-express-middleware';
import express from 'express';

// 初始化 Express app
const app = express();

app.use(expressMiddleware);

export default {
  dev: {
    setupMiddlewares: [
      (middleware) => {
        middleware.unshift(app);
      },
    ],
  },
};
```

## 自定义 Server

如果你希望将 Rsbuild dev server 集成到自定义的 server 中，可以通过 Rsbuild `createDevServer` 方法获取 Rsbuild dev server 的实例方法，进行按需调用。

详情可参考 [Rsbuild - createDevServer](/api/javascript-api/instance#rsbuildcreatedevserver)。
